home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / MacGzip 1.0 / source / GNU / gzip.c < prev    next >
Text File  |  1995-12-30  |  33KB  |  1,393 lines

  1. /*
  2.  * gzip.c for MacGzip 1.0
  3.  * SPDsoft, August 22, 1995
  4.  * very little to do with original gzip.c (gzip.c.cln in this distribution)
  5.  */
  6.  
  7. /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
  8.  * Copyright (C) 1992-1993 Jean-loup Gailly
  9.  * The unzip code was written and put in the public domain by Mark Adler.
  10.  * Portions of the lzw code are derived from the public domain 'compress'
  11.  * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
  12.  * Ken Turkowski, Dave Mack and Peter Jannesen.
  13.  *
  14.  */
  15.  
  16.  
  17. #ifdef RCSID
  18. static char rcsid[] = "$Id: gzip.c,v 0.24 1993/06/24 10:52:07 jloup Exp $";
  19. #endif
  20.  
  21. #include <signal.h>
  22. #include <errno.h>
  23. #include <stdlib.h>
  24.  
  25. #include <setjmp.h>
  26.  
  27. #include "tailor.h"
  28.  
  29. #include "MacIO.h"
  30. #include "FileTypes.h"
  31. #include "Prefs.h"
  32. #include "Globals.h"
  33. #include "GzErrors.h"
  34. #include "GzPStrings.h"
  35.  
  36. #include "gzip.h"
  37. #include "lzw.h"
  38. #include "revision.h"
  39.  
  40.  
  41. typedef RETSIGTYPE (*sig_type) OF((int));
  42.  
  43.  
  44.  
  45. #ifndef MAX_PATH_LEN
  46. #  define MAX_PATH_LEN   255 /* max pathname length */
  47. #endif
  48.  
  49.  
  50. #define PART_SEP "."
  51.  
  52.         /* global buffers */
  53.  
  54. DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
  55. DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  56. DECLARE(ush, d_buf,  DIST_BUFSIZE);
  57. DECLARE(uch, window, 2L*WSIZE);
  58. #ifndef MAXSEG_64K
  59.     DECLARE(ush, tab_prefix, 1L<<BITS);
  60. #else
  61.     DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
  62.     DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
  63. #endif
  64.  
  65.         /* local variables */
  66.  
  67. int macbinary        = 0;
  68. int ascii            = 0;        /* convert end-of-lines to local OS conventions */
  69. int to_stdout        = 0;        /* output to stdout (-c) */
  70. int decompress        = 0;        /* decompress (-d) */
  71. int force            = 0;        /* don't ask questions, compress links (-f) */
  72. int no_name            = -1;        /* don't save or restore the original file name */
  73. int no_time            = -1;        /* don't save or restore the original file time */
  74. int list            = 0;        /* list the file contents (-l) */
  75. int verbose            = 0;        /* be verbose (-v) */
  76. int quiet            = 0;        /* be very quiet (-q) */
  77. int test            = 0;        /* test .gz file integrity */
  78. char *progname        ="gzip";    /* program name */
  79. int maxbits            = BITS;        /* max bits per code for LZW */
  80. int method            = DEFLATED;    /* compression method */
  81. int level            = 6;        /* compression level */
  82. int exit_code        = OK;        /* program exit code */
  83. int save_orig_name;                /* set if original name must be saved */
  84. int last_member;                /* set for .zip and .Z files */
  85. int part_nb;                    /* number of parts in .gz file */
  86. long time_stamp;                /* original time stamp (modification time) */
  87. long ifile_size;                /* input file size, -1 for devices (debug only) */
  88. char z_suffix[MAX_SUFFIX+1];    /* default suffix (can be set with --suffix) */
  89. int  z_len;                        /* strlen(z_suffix) */
  90.  
  91. long bytes_in;             /* number of input bytes */
  92. long bytes_out;            /* number of output bytes */
  93. long total_in = 0;         /* input bytes for all files */
  94. long total_out = 0;        /* output bytes for all files */
  95. char ifname[MAX_PATH_LEN]; /* input file name */
  96. char ofname[MAX_PATH_LEN]; /* output file name */
  97. int  remove_ofname = 0;       /* remove output file on error */
  98. struct stat istat;         /* status for input file */
  99. int  ifd;                  /* input file descriptor */
  100. int  ofd;                  /* output file descriptor */
  101. unsigned insize;           /* valid bytes in inbuf */
  102. unsigned inptr;            /* index of next byte to be processed in inbuf */
  103. unsigned outcnt;           /* bytes in output buffer */
  104.  
  105. jmp_buf env;                /* for setjmp (do_exit) */
  106.  
  107. FSSpec    ifs,
  108.         ofs;
  109.         
  110. /* local functions */
  111.  
  112. local void treat_file( FSSpec *fs );
  113. local int create_outfile OF((void));
  114. local char *get_suffix  OF((char *name));
  115. local int get_istat( FSSpec *ifs, struct stat *sbuf);
  116. local int  make_ofname  OF((void));
  117. local void shorten_name  OF((char *name));
  118. local int  get_method   OF((int in));
  119. local int  check_ofname OF((void));
  120. local void copy_stat    OF((struct stat *ifstat));
  121. local void do_exit      OF((int exitcode));
  122. int (*work) OF((int infile, int outfile)) = zip; /* function to call */
  123. local void reset_times (FSSpec *fs, struct stat *statb);
  124.  
  125. local Boolean init_globals( FSSpec *fs );
  126. OSErr PromptGZIPFile( FSSpec *fs, Str255 prompt );
  127. OSErr MakeOFSSpec( FSSpec *fs , Str255 prompt );
  128.  
  129. #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
  130.  
  131. int gzip ( FSSpec *fs );
  132.  
  133.  
  134. /* ======================================================================== */
  135. int gzip ( FSSpec *fs )
  136. {
  137.     int file_count;     /* number of files to precess */
  138.     int proglen;        /* length of progname */
  139.  
  140.     
  141.     if ( setjmp(env) != 0)
  142.     {
  143.         /* this is executed upon process error */
  144.         
  145.         return ERROR;
  146.     }
  147.     
  148.     
  149.     
  150.     proglen = 4;
  151.  
  152.     if (get_istat(fs, &istat) != OK) return ERROR;
  153.     if (init_globals( fs )) return ERROR;
  154.     
  155.     ifs = *fs;
  156.     ofs = *fs;
  157.     
  158.     /* By default, save name and timestamp on compression but do not
  159.      * restore them on decompression.
  160.      */
  161.     if (no_time < 0) no_time = decompress;
  162.     if (no_name < 0) no_name = decompress;
  163.  
  164.     file_count = 1;
  165.  
  166.     if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX)
  167.     {
  168.         /* this should never happend (suffix is tested in PrefsDlg.c) */
  169.  
  170.         DoError(INPUT_ERR, WARN_ERR, "%s: incorrect suffix '%s'", progname, z_suffix);
  171.         do_exit(ERROR);
  172.     }
  173.     
  174. /*    if (do_lzw && !decompress) work = lzw; *//* not supported in gzip 1.2.4 */
  175.  
  176.     /*
  177.      * Allocate all global buffers (for DYN_ALLOC option)
  178.      */
  179.     
  180.     ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
  181.     ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  182.     ALLOC(ush, d_buf,  DIST_BUFSIZE);
  183.     ALLOC(uch, window, 2L*WSIZE);
  184. #ifndef MAXSEG_64K
  185.     ALLOC(ush, tab_prefix, 1L<<BITS);
  186. #else
  187.     ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
  188.     ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
  189. #endif
  190.  
  191.     /* And get to work */
  192.  
  193.     treat_file( &ifs );
  194.  
  195.  
  196. /*    do_list(-1, -1);  *//* print totals */
  197.  
  198.     do_exit(exit_code);
  199.     return exit_code; /* just to avoid lint warning */
  200. }
  201.  
  202.  
  203. /* ========================================================================
  204.  * Compress or decompress the given file
  205.  */
  206. local void treat_file( FSSpec *fs )
  207. {
  208.     int        imode;
  209.     
  210.     
  211.  
  212.     if ( !decompress && macbinary )
  213.         ifile_size = istat.st_mbsize;
  214.     else
  215.         ifile_size = istat.st_size;
  216.         
  217.     time_stamp = no_time ? 0 : istat.st_mtime;
  218.  
  219.     /* Generate output file name. For -r and (-t or -l), skip files
  220.      * without a valid gzip suffix (check done in make_ofname).
  221.      */
  222.      
  223.     if (make_ofname() != OK) return;
  224.     
  225.     /* Here we don't have the true output fname (when decompress)
  226.      * just the iname without the suffix. We will wait to 'create_outfile'
  227.      */
  228.     
  229.     if ( decompress )
  230.     {
  231.         imode = OM_RDONLY | OM_BINARY;
  232.     }
  233.     else
  234.     {
  235.         if ( macbinary == 1) imode = OM_RDONLY | OM_MACBINARY;
  236.         else if ( ascii == 1) imode = OM_RDONLY | OM_TEXT;
  237.         else imode = OM_RDONLY | OM_BINARY;
  238.     }
  239.     
  240.     ifd = fs_open( fs, imode );
  241.  
  242.     if (ifd == -1)
  243.     {
  244.         DoError(STDC_ERR, WARN_ERR, "%s: %s:", progname, ifname);
  245.         exit_code = ERROR;
  246.         return;
  247.     }
  248.     
  249.     clear_bufs(); /* clear input and output buffers */
  250.     part_nb = 0;
  251.  
  252.     if (decompress)
  253.     {
  254.         method = get_method(ifd); /* updates ofname if original given */
  255.         if (method < 0)
  256.         {
  257.             close(ifd);
  258.             return;               /* error message already emitted */
  259.         }
  260.     }
  261.     /*
  262.      * Here we have enough info to set decompress flags.
  263.      *
  264.      *        even if we are trying MacBinary, we should try to
  265.      *        map the file, since MB translation can fail, if
  266.      *        the file is not really a MB gziped file, and then we'll
  267.      *        have to switch to the default mode.
  268.      */
  269.  
  270.     if (create_outfile() != OK) return;
  271.  
  272.  
  273.     /* Keep the name even if not truncated except with --no-name: */
  274.     if (!save_orig_name) save_orig_name = !no_name;
  275.  
  276.  
  277.     /*
  278.      * Open progress window...
  279.      */
  280.      
  281.     gApp.Working = TRUE;
  282.     SetMMString( "g%szip (%s) %s", decompress ? "un" : "" , macbinary ? "MBII" : ( ascii ? "ASCII" : "bin" ), ofname );
  283.     InitMovableModal( ifile_size, &fd_table[ifd].pos );
  284.     DoSystemTask();
  285.  
  286.     /* Actually do the compression/decompression. Loop over zipped members.
  287.      */
  288.     for (;;)
  289.     {
  290.         if ((*work)(ifd, ofd) != OK)
  291.         {
  292.             method = -1; /* force cleanup */
  293.             break;
  294.         }
  295.     
  296.         if (!decompress || last_member || inptr == insize) break;
  297.         /* end of file */
  298.  
  299.         method = get_method(ifd);
  300.         if (method < 0) break;    /* error message already emitted */
  301.         bytes_out = 0;            /* required for length check */
  302.     }
  303.  
  304.     close(ifd);
  305.     
  306.     DoSystemTask();
  307.  
  308.     if ( close(ofd) )
  309.     {
  310.         write_error();
  311.     }
  312.     
  313.     if (method == -1)
  314.     {
  315.         fs_unlink ( &ofs );
  316.         return;
  317.     }
  318.     
  319.     copy_stat(&istat);
  320. }
  321.  
  322. /* ========================================================================
  323.  * Create the output file. Return OK or ERROR.
  324.  * Try several times if necessary to avoid truncating the z_suffix. For
  325.  * example, do not create a compressed file of name "1234567890123."
  326.  * Sets save_orig_name to true if the file name has been truncated.
  327.  * IN assertions: the input file has already been open (ifd is set) and
  328.  *   ofname has already been updated if there was an original name.
  329.  * OUT assertions: ifd and ofd are closed in case of error.
  330.  */
  331.  
  332. /*
  333.  * MacGzip:
  334.  *
  335.  *        if gApp.Prompt we must sfgetfile with ofname,
  336.  *        anyway, if we are decompressing a MB file we only will know
  337.  *        its name at the moment of create it.
  338.  *
  339.  */
  340.  
  341. local int create_outfile()
  342. {
  343.     int flags;
  344.  
  345.     
  346.     if (check_ofname() != OK)
  347.     {
  348.         close(ifd);
  349.         return ERROR;
  350.     }
  351.     
  352.     
  353.     /* set flags */
  354.  
  355.     if ( decompress )
  356.     {
  357.         gSufMap.Found = FALSE;
  358.         ascii = 0;
  359.         macbinary = 0;
  360.         
  361.         /* even if we are trying mb, we must check suffix mapping */
  362.     
  363.         macbinary = gPrefs.Decompress.TryMB ? 1 : 0;
  364.         
  365.         if ( gPrefs.Decompress.Mode == kDeco_MASCII )
  366.         {
  367.             gSufMap.Binary = FALSE;
  368.             gSufMap.MacFile = FALSE;
  369.         }
  370.         else
  371.         {
  372.             gSufMap.Binary = TRUE;
  373.             gSufMap.MacFile = FALSE;
  374.         }
  375.         
  376.         if (( gPrefs.Decompress.Keys ) && ( gApp.KeysMode != 0 ))
  377.         {
  378.             switch ( gApp.KeysMode )
  379.             {
  380.                 case kAppKeyASCII:
  381.                     gSufMap.Binary = FALSE;
  382.                     gSufMap.MacFile = FALSE;
  383.                     macbinary = 0;
  384.                     break;
  385.                 case kAppKeyBin:
  386.                     gSufMap.Binary = TRUE;
  387.                     gSufMap.MacFile = FALSE;
  388.                     macbinary = 0;
  389.                     break;
  390.                 case kAppKeyMBin:
  391.                     gSufMap.Binary = TRUE;
  392.                     gSufMap.MacFile = TRUE;
  393.                     macbinary = 1;
  394.                     break;
  395.                 default:
  396.                     DoError(PROG_ERR,WARN_ERR,"Mala suerte, error del programador");
  397.                     break;
  398.             }
  399.         }
  400.         else
  401.         {
  402.             if ( gPrefs.Decompress.IC )
  403.             {
  404.                 ResolveFileType( &ofs, nil, &gSufMap, kRFTDownload | kRFTFromSpec | kRFTIC );
  405.             }
  406.             else if ( gPrefs.Decompress.Fetch )
  407.             {
  408.                 ResolveFileType( &ofs, nil, &gSufMap, kRFTDownload | kRFTFromSpec | kRFTFetch );
  409.             }
  410.         }
  411.         
  412.         if ( ! gSufMap.Found )
  413.         {
  414.             if ( gSufMap.Binary )
  415.             {
  416.                 gSufMap.Type = gPrefs.Decompress.BinType;
  417.                 gSufMap.Creator = gPrefs.Decompress.BinCreator;
  418.             }
  419.             else
  420.             {
  421.                 gSufMap.Type = 'TEXT';
  422.                 gSufMap.Creator = gPrefs.Decompress.TextCreator;
  423.             }
  424.         }
  425.         
  426.         ascii = gSufMap.Binary ? 0 : 1;
  427.         
  428.         
  429.         flags = OM_WRONLY | ( ascii ?  OM_TEXT : OM_BINARY );
  430.         if ( macbinary ) flags |= OM_MACBINARY;
  431.         
  432.         DefCreator = gSufMap.Creator;
  433.         DefType = gSufMap.Type;
  434.         
  435.     }
  436.     else /* compress */
  437.     {
  438.         flags = OM_WRONLY | OM_BINARY;
  439.                 
  440.         DefCreator = 'Gzip';    /* externals in MacIO.c */
  441.         DefType = 'Gzip';
  442.     }
  443.     
  444.     
  445.     
  446.     
  447.     /* Create the output file */
  448.     remove_ofname = 1;
  449.     ofd = fs_open( &ofs, flags );
  450.     if (ofd == -1)
  451.     {
  452.         DoError(STDC_ERR, WARN_ERR, "Can't open %s", ofname );
  453.  
  454.         close(ifd);
  455.         exit_code = ERROR;
  456.         return ERROR;
  457.     }
  458.  
  459.     
  460.     return OK;
  461. }
  462.  
  463. /***************************************************************************
  464.  * Return a pointer to the 'z' suffix of a file name, or NULL. For all
  465.  * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
  466.  * accepted suffixes, in addition to the value of the --suffix option.
  467.  * ".tgz" is a useful convention for tar.z files on systems limited
  468.  * to 3 characters extensions. On such systems, ".?z" and ".??z" are
  469.  * also accepted suffixes. For Unix, we do not want to accept any
  470.  * .??z suffix as indicating a compressed file; some people use .xyz
  471.  * to denote volume data.
  472.  *   On systems allowing multiple versions of the same file (such as VMS),
  473.  * this function removes any version suffix in the given name.
  474.  */
  475. local char *get_suffix(name)
  476.     char *name;
  477. {
  478.     int nlen, slen;
  479.     char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
  480.     static char *known_suffixes[] =
  481.        {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
  482. #ifdef MAX_EXT_CHARS
  483.           "z",
  484. #endif
  485.           NULL};
  486.     char **suf = known_suffixes;
  487.  
  488.     if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
  489.  
  490. #ifdef SUFFIX_SEP
  491.     /* strip a version number from the file name */
  492.     {
  493.     char *v = strrchr(name, SUFFIX_SEP);
  494.      if (v != NULL) *v = '\0';
  495.     }
  496. #endif
  497.     nlen = strlen(name);
  498.     if (nlen <= MAX_SUFFIX+2) {
  499.         strcpy(suffix, name);
  500.     } else {
  501.         strcpy(suffix, name+nlen-MAX_SUFFIX-2);
  502.     }
  503.     strlwr(suffix);
  504.     slen = strlen(suffix);
  505.     do {
  506.        int s = strlen(*suf);
  507.        if (slen > s && suffix[slen-s-1] != PATH_SEP
  508.            && strequ(suffix + slen - s, *suf)) {
  509.            return name+nlen-s;
  510.        }
  511.     } while (*++suf != NULL);
  512.  
  513.     return NULL;
  514. }
  515.  
  516.  
  517. /***************************************************************************
  518.  * Set ifname to the input file name (with a suffix appended if necessary)
  519.  * and istat to its stats. For decompression, if no file exists with the
  520.  * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
  521.  * For MSDOS, we try only z_suffix and z.
  522.  * Return OK or ERROR.
  523.  */
  524.  
  525. /*
  526.  * For MacOS:
  527.  *
  528.  * Set ifname to the input file name
  529.  *
  530.  *    - we dont need to append anything
  531.  *    - no stat
  532.  */
  533.  
  534. local int get_istat( FSSpec *ifs, struct stat *sbuf)
  535. {
  536.     Str255ToCStr( ifname, ifs->name );
  537.     
  538.     errno = 0;
  539.  
  540.     if ( fs_stat(ifs, sbuf) == 0)
  541.         return OK;
  542.     else
  543.     {
  544.         exit_code = ERROR;
  545.         return ERROR;
  546.     }
  547. }
  548.  
  549. /***************************************************************************
  550.  * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
  551.  * Sets save_orig_name to true if the file name has been truncated.
  552.  */
  553. local int make_ofname()
  554. {
  555.     char *suff;            /* ofname z suffix */
  556.  
  557.     strcpy(ofname, ifname);
  558.     /* strip a version number if any and get the gzip suffix if present: */
  559.     suff = get_suffix(ofname);
  560.  
  561.     if (decompress)
  562.     {
  563.         if (suff == NULL)
  564.         {
  565.             WARN((stderr,"%s: %s: unknown suffix -- ignored", progname, ifname));
  566.             return WARNING;
  567.         }
  568.         
  569.         /* Make a special case for .tgz and .taz: */
  570.         strlwr(suff);
  571.         if (strequ(suff, ".tgz") || strequ(suff, ".taz"))
  572.         {
  573.             strcpy(suff, ".tar");
  574.         }
  575.         else
  576.         {
  577.             *suff = '\0'; /* strip the z suffix */
  578.         }
  579.         /* ofname might be changed later if infile contains an original name */
  580.     }
  581.     else /* compress */
  582.     if (suff != NULL)
  583.     {
  584.         DoStdIO(stderr, "%s: %s already has %s suffix -- unchanged",
  585.             progname, ifname, suff);
  586.     
  587.         if (exit_code == OK) exit_code = WARNING;
  588.         return WARNING;
  589.     }
  590.     else
  591.     {
  592.         save_orig_name = 0;
  593.         strcat(ofname, z_suffix);
  594.         
  595.         if ( macbinary == 1 )
  596.             strcat(ifname, ".bin");
  597.             
  598.     } /* decompress ? */
  599.     
  600.     return OK;
  601. }
  602.  
  603.  
  604. /* ========================================================================
  605.  * Check the magic number of the input file and update ofname if an
  606.  * original name was given and to_stdout is not set.
  607.  * Return the compression method, -1 for error, -2 for warning.
  608.  * Set inptr to the offset of the next byte to be processed.
  609.  * Updates time_stamp if there is one and --no-time is not used.
  610.  * This function may be called repeatedly for an input file consisting
  611.  * of several contiguous gzip'ed members.
  612.  * IN assertions: there is at least one remaining compressed member.
  613.  *   If the member is a zip file, it must be the only one.
  614.  */
  615. local int get_method(int in) /* input file descriptor */
  616. {
  617.     uch flags;     /* compression flags */
  618.     char magic[2]; /* magic header */
  619.     ulg stamp;     /* time stamp */
  620.  
  621.  
  622.     magic[0] = (char)get_byte();
  623.     magic[1] = (char)get_byte();
  624.  
  625.     method = -1;                 /* unknown yet */
  626.     part_nb++;                   /* number of parts in gzip file */
  627.     header_bytes = 0;
  628.     last_member = RECORD_IO;
  629.     /* assume multiple members in gzip file except for record oriented I/O */
  630.  
  631.     if (memcmp(magic, GZIP_MAGIC, 2) == 0
  632.         || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0)
  633.     {
  634.         method = (int)get_byte();
  635.         if (method != DEFLATED)
  636.         {
  637.             DoError(INPUT_ERR,WARN_ERR,
  638.             "%s: %s: unknown method %d -- get newer version of gzip",
  639.             progname, ifname, method);
  640.             exit_code = ERROR;
  641.             return -1;
  642.         }
  643.         
  644.         work = unzip;
  645.         flags  = (uch)get_byte();
  646.  
  647.         if ((flags & ENCRYPTED) != 0)
  648.         {
  649.             DoError(INPUT_ERR,WARN_ERR,
  650.             "%s: %s is encrypted -- get newer version of gzip",
  651.             progname, ifname);
  652.             exit_code = ERROR;
  653.             return -1;
  654.         }
  655.         
  656.         if ((flags & CONTINUATION) != 0)
  657.         {
  658.             DoError(INPUT_ERR,WARN_ERR,
  659.             "%s: %s is a a multi-part gzip file -- get newer version of gzip",
  660.             progname, ifname);
  661.             exit_code = ERROR;
  662.             if (force <= 1) return -1;
  663.         }
  664.         
  665.         if ((flags & RESERVED) != 0)
  666.         {
  667.             DoError(INPUT_ERR,WARN_ERR,
  668.             "%s: %s has flags 0x%x -- get newer version of gzip",
  669.             progname, ifname, flags);
  670.             exit_code = ERROR;
  671.             if (force <= 1) return -1;
  672.         }
  673.         
  674.         stamp  = (ulg)get_byte();
  675.         stamp |= ((ulg)get_byte()) << 8;
  676.         stamp |= ((ulg)get_byte()) << 16;
  677.         stamp |= ((ulg)get_byte()) << 24;
  678.  
  679.         if (stamp != 0 && !no_time) time_stamp = stamp + MAC_TIMEOFFSET;
  680.         
  681.         (void)get_byte();  /* Ignore extra flags for the moment */
  682.         (void)get_byte();  /* Ignore OS type for the moment */
  683.  
  684.         if ((flags & CONTINUATION) != 0)
  685.         {
  686.             unsigned part = (unsigned)get_byte();
  687.             part |= ((unsigned)get_byte())<<8;
  688.         }
  689.         
  690.         if ((flags & EXTRA_FIELD) != 0)
  691.         {
  692.             unsigned len = (unsigned)get_byte();
  693.             len |= ((unsigned)get_byte())<<8;
  694.             while (len--) (void)get_byte();
  695.         }
  696.  
  697.         /* Get original file name if it was truncated */
  698.         
  699.         if ((flags & ORIG_NAME) != 0)
  700.         {
  701.             if (no_name || part_nb > 1)
  702.             {
  703.                 /* Discard the old name */
  704.                 char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
  705.                 do {c=get_byte();} while (c != 0);
  706.             }
  707.             else
  708.             {
  709.                 char *p = ofname;
  710.                 char *base = p;
  711.                 for (;;)
  712.                 {
  713.                     *p = (char)get_char();
  714.                     if (*p++ == '\0') break;
  715.                     if (p >= ofname+sizeof(ofname))
  716.                     {
  717.                         error("corrupted input -- file name too large");
  718.                     }
  719.                 }
  720.                 /* If necessary, adapt the name to local OS conventions: */
  721.  
  722.                 MAKE_LEGAL_NAME(base);
  723.                 
  724.                 /*
  725.                  * it still can be too long, and is is a MacBinary file,
  726.                  * it won't be the actual name, either
  727.                  */
  728.                 
  729.                 if (base) list=0; /* avoid warning about unused variable */
  730.             } /* no_name || to_stdout */
  731.         } /* ORIG_NAME */
  732.  
  733.         /* Discard file comment if any */
  734.         if ((flags & COMMENT) != 0)
  735.         {
  736.             while (get_char() != 0) /* null */ ;
  737.         }
  738.     
  739.         if (part_nb == 1)
  740.         {
  741.             header_bytes = inptr + 2*sizeof(long); /* include crc and size */
  742.         }
  743.  
  744.     }
  745.     else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
  746.             && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0)
  747.     {
  748.         /* To simplify the code, we support a zip file when alone only.
  749.          * We are thus guaranteed that the entire local header fits in inbuf.
  750.          */
  751.         inptr = 0;
  752.         work = unzip;
  753.         if (check_zipfile(in) != OK) return -1;
  754.         /* check_zipfile may get ofname from the local header */
  755.         last_member = 1;
  756.  
  757.     }
  758.     else if (memcmp(magic, PACK_MAGIC, 2) == 0)
  759.     {
  760.         work = unpack;
  761.         method = PACKED;
  762.     }
  763.     else if (memcmp(magic, LZW_MAGIC, 2) == 0)
  764.     {
  765.         work = unlzw;
  766.         method = COMPRESSED;
  767.         last_member = 1;
  768.     }
  769.     else if (memcmp(magic, LZH_MAGIC, 2) == 0)
  770.     {
  771.         work = unlzh;
  772.         method = LZHED;
  773.         last_member = 1;
  774.     }
  775.     else if (force && to_stdout && !list)
  776.     {    /* pass input unchanged */
  777.         method = STORED;
  778.         work = copy;
  779.         inptr = 0;
  780.         last_member = 1;
  781.     }
  782.     if (method >= 0) return method;
  783.  
  784.     if (part_nb == 1)
  785.     {
  786.         DoError(INPUT_ERR,WARN_ERR, "%s: %s: not in gzip format", progname, ifname);
  787.         exit_code = ERROR;
  788.         return -1;
  789.     }
  790.     else
  791.     {
  792.         WARN((stderr, "%s: %s: decompression OK, trailing garbage ignored",
  793.           progname, ifname));
  794.         return -2;
  795.     }
  796. }
  797.  
  798.  
  799.  
  800. /* ========================================================================
  801.  * Shorten the given name by one character, or replace a .tar extension
  802.  * with .tgz. Truncate the last part of the name which is longer than
  803.  * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
  804.  * has only parts shorter than MIN_PART truncate the longest part.
  805.  * For decompression, just remove the last character of the name.
  806.  *
  807.  * IN assertion: for compression, the suffix of the given name is z_suffix.
  808.  */
  809. local void shorten_name(name)
  810.     char *name;
  811. {
  812.     int len;                 /* length of name without z_suffix */
  813.     char *trunc = NULL;      /* character to be truncated */
  814.     int plen;                /* current part length */
  815.     int min_part = MIN_PART; /* current minimum part length */
  816.     char *p;
  817.  
  818.     len = strlen(name);
  819.     if (decompress) {
  820.     if (len <= 1) error("name too short");
  821.     name[len-1] = '\0';
  822.     return;
  823.     }
  824.     p = get_suffix(name);
  825.     if (p == NULL) error("can't recover suffix");
  826.     *p = '\0';
  827.     save_orig_name = 1;
  828.  
  829.     /* compress 1234567890.tar to 1234567890.tgz */
  830.     if (len > 4 && strequ(p-4, ".tar")) {
  831.     strcpy(p-4, ".tgz");
  832.     return;
  833.     }
  834.     /* Try keeping short extensions intact:
  835.      * 1234.678.012.gz -> 123.678.012.gz
  836.      */
  837.     do {
  838.     p = strrchr(name, PATH_SEP);
  839.     p = p ? p+1 : name;
  840.     while (*p) {
  841.         plen = strcspn(p, PART_SEP);
  842.         p += plen;
  843.         if (plen > min_part) trunc = p-1;
  844.         if (*p) p++;
  845.     }
  846.     } while (trunc == NULL && --min_part != 0);
  847.  
  848.     if (trunc != NULL) {
  849.     do {
  850.         trunc[0] = trunc[1];
  851.     } while (*trunc++);
  852.     trunc--;
  853.     } else {
  854.     trunc = strrchr(name, PART_SEP[0]);
  855.     if (trunc == NULL) error("internal error in shorten_name");
  856.     if (trunc[1] == '\0') trunc--; /* force truncation */
  857.     }
  858.     strcpy(trunc, z_suffix);
  859. }
  860.  
  861. /* ========================================================================
  862.  * If compressing to a file, check if ofname is not ambiguous
  863.  * because the operating system truncates names. Otherwise, generate
  864.  * a new ofname and save the original name in the compressed file.
  865.  * If the compressed file already exists, ask for confirmation.
  866.  *    The check for name truncation is made dynamically, because different
  867.  * file systems on the same OS might use different truncation rules (on SVR4
  868.  * s5 truncates to 14 chars and ufs does not truncate).
  869.  *    This function returns -1 if the file must be skipped, and
  870.  * updates save_orig_name if necessary.
  871.  * IN assertions: save_orig_name is already set if ofname has been
  872.  * already truncated because of NO_MULTIPLE_DOTS. The input file has
  873.  * already been open and istat is set.
  874.  */
  875.  
  876. /*
  877.  * MacGzip
  878.  *
  879.  * IN:
  880.  *        ofname generated/extracted from .gz
  881.  *        ofs = ifs
  882.  */
  883. #define MAXPATHLEN 31
  884.  
  885. local int check_ofname()
  886. {
  887.     errno = 0;
  888.     while ( strlen( ofname ) > MAXPATHLEN)
  889.         shorten_name(ofname);
  890.  
  891.     CStrToStr255( ofs.name, ofname );
  892.     
  893.     if ( !decompress )
  894.     {
  895.         if ( noErr != (err = MakeOFSSpec( &ofs, "\pSave gzip file:" )))
  896.         {
  897.             exit_code = ERROR;
  898.             return ERROR;
  899.         }
  900.     }
  901.     return OK;
  902. }
  903.  
  904.  
  905. /* ========================================================================
  906.  * Set the access and modification times from the given stat buffer.
  907.  */
  908. local void reset_times (FSSpec *fs, struct stat *statb)
  909. {
  910.     CInfoPBRec        info;
  911.     
  912.     info.hFileInfo.ioNamePtr                = fs->name;
  913.     info.hFileInfo.ioVRefNum                 = fs->vRefNum;
  914.     info.hFileInfo.ioFDirIndex                = 0;
  915.     info.hFileInfo.ioDirID                    = fs->parID;
  916.  
  917.  
  918.     if ( noErr != ( err = PBGetCatInfo( (CInfoPBPtr) &info, false ) ) )
  919.     {
  920.         errno = err;
  921.     }
  922.     else
  923.     {
  924.         info.hFileInfo.ioNamePtr                = fs->name;
  925.         info.hFileInfo.ioVRefNum                 = fs->vRefNum;
  926.         info.hFileInfo.ioFDirIndex                = 0;
  927.         info.hFileInfo.ioDirID                    = fs->parID;
  928.         
  929.         info.hFileInfo.ioFlCrDat = statb->st_ctime;
  930.         info.hFileInfo.ioFlMdDat = statb->st_mtime;
  931.  
  932.         err = errno = PBSetCatInfo( (CInfoPBPtr) &info, false );
  933.         
  934.     }
  935. }
  936.  
  937.  
  938.  
  939. /* ========================================================================
  940.  * Copy modes, times, ownership from input file to output file.
  941.  * IN assertion: to_stdout is false.
  942.  */
  943. local void copy_stat(ifstat)
  944.     struct stat *ifstat;
  945. {
  946.     if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp)
  947.     {
  948. /*        buf->st_atime = info->hFileInfo.ioFlMdDat;
  949.  *        buf->st_mtime = info->hFileInfo.ioFlMdDat;
  950.  *        buf->st_ctime = info->hFileInfo.ioFlCrDat;
  951.  */
  952.         ifstat->st_mtime =
  953.         ifstat->st_atime =
  954.         ifstat->st_ctime = time_stamp;
  955.         
  956.     }
  957.     reset_times( &ofs, ifstat);
  958.  
  959.  
  960.     remove_ofname = 0;
  961.     /* It's now safe to remove the input file: */
  962.  
  963.     if ( !gPrefs.Misc.KeepOriginal )
  964.         if ( fs_unlink(&ifs))
  965.         {
  966.             DoError(STDC_ERR, WARN_ERR, "Can't delete %s", ifname);
  967.         }
  968. }
  969.  
  970.  
  971. /* ========================================================================
  972.  * Free all dynamically allocated variables and exit with the given code.
  973.  */
  974. local void do_exit(exitcode)
  975.     int exitcode;
  976. {
  977.  
  978.     FREE(inbuf);
  979.     FREE(outbuf);
  980.     FREE(d_buf);
  981.     FREE(window);
  982. #ifndef MAXSEG_64K
  983.     FREE(tab_prefix);
  984. #else
  985.     FREE(tab_prefix0);
  986.     FREE(tab_prefix1);
  987. #endif
  988.     if (exitcode==0)
  989.     {
  990.         return;
  991.     }
  992.     else
  993.     {
  994.         err = errno = noErr;
  995.         
  996.         longjmp( env, exitcode );
  997.         /* this is not executed */
  998.         DoError(PROG_ERR, QUIT_ERR, "Serious fail, quitting… (%d)", exitcode );
  999.     }
  1000. }
  1001.  
  1002. /* ========================================================================
  1003.  * Signal and error handler.
  1004.  */
  1005. RETSIGTYPE abort_gzip()
  1006. {
  1007.     if (fd_busy[ifd] == 1)
  1008.     {
  1009.         close(ifd);
  1010.     }
  1011.     
  1012.     if ((remove_ofname) && (fd_busy[ofd] == 1))
  1013.     {
  1014.         close(ofd);
  1015.         
  1016.         if ( fd_table[ofd].new == 1 )
  1017.             fs_unlink (&ofs);
  1018.     }
  1019.     do_exit(ERROR);
  1020. }
  1021.  
  1022. /* ========================================================================
  1023.  * init the options
  1024.  *
  1025.  *        Input:
  1026.  *                - gPrefs
  1027.  *                - ifs
  1028.  *                - startup keys (in gApp.KeysMode and KeysOp)
  1029.  *                - Op ( from expand to, compress to)
  1030.  */
  1031.  
  1032. #define kAskRFID    154
  1033. #define kAskRF_mb    1
  1034. #define kAskRF_not    2
  1035. #define kAskRF_quit    3
  1036.  
  1037. local Boolean init_globals( FSSpec *fs )
  1038. {    
  1039.     /* decompress (-d) */
  1040.     /*
  1041.      * this can be set by:
  1042.      *        dropping with 'opt' => force compress
  1043.      *        dropping with 'ctrl' => force decompress
  1044.      *            or
  1045.      *        Menu 'Expand'/'Compress' -> Op ( keys already have modify this )
  1046.      *            else
  1047.      *        File type is 'Gzip' (or similar) / or DefaultCompress
  1048.      */
  1049.     Boolean error = FALSE;
  1050.     
  1051.     switch ( gApp.Op )
  1052.     {
  1053.         case kMisc_gzip:
  1054.             decompress = 0;
  1055.             break;
  1056.             
  1057.         case kMisc_gunzip:
  1058.             decompress = 1;
  1059.             break;
  1060.             
  1061.         case kMisc_auto:
  1062.             
  1063.             
  1064.             decompress= 
  1065.                 (( gPrefs.Misc.DefaultOp == kMisc_gunzip ) ||
  1066.                 (
  1067.                     ( gPrefs.Misc.DefaultOp == kMisc_auto ) &&
  1068.                      (
  1069.                          (gSufMap.Type == 'Gzip') ||
  1070.                         (gSufMap.Type == 'ZIVU') ||
  1071.                         (gSufMap.Type == 'ZIVM') ||
  1072.                         (gSufMap.Type == 'pZIP')
  1073.                     )
  1074.                 ));
  1075.                 
  1076.             break;
  1077.             
  1078.         default:
  1079.             DoError(PROG_ERR, QUIT_ERR, "there is a bug somewhere...");
  1080.             break;
  1081.     }
  1082.     
  1083.     force = gPrefs.gzip.Force;        /* don't ask questions, compress links (-f) */
  1084.     
  1085.     
  1086.     no_name = -1;     /* don't save or restore the original file name */
  1087.     no_time = -1;     /* don't save or restore the original file time */
  1088.  
  1089.     if ( gPrefs.gzip.NoName )
  1090.         no_name = no_time = 1;
  1091.         
  1092.     if ( gPrefs.gzip.Name )
  1093.         no_name = no_time = 0;
  1094.         
  1095.     verbose = 0;      /* be verbose (-v) */
  1096.     quiet = 0;        /* be very quiet (-q) */
  1097.     maxbits = BITS;   /* max bits per code for LZW */
  1098.     method = DEFLATED;/* compression method */
  1099.         
  1100.     level = (int) gPrefs.gzip.Level;        /* compression level */
  1101.         
  1102.     
  1103.     exit_code = OK;   /* program exit code */
  1104.     total_in = 0;         /* input bytes for all files */
  1105.     total_out = 0;        /* output bytes for all files */
  1106.     remove_ofname = 0;       /* remove output file on error */
  1107.     work = zip;
  1108.  
  1109.  
  1110.     if (( gPrefs.gzip.UseCustomSuffix ) && ( decompress || (!decompress && !gPrefs.gzip.GunzipSuffix)))
  1111.     {
  1112.         Str255ToCStr( z_suffix, gPrefs.gzip.Suffix );
  1113.     }
  1114.     else
  1115.     {
  1116.         strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1);
  1117.     }
  1118.     z_len = strlen(z_suffix);
  1119.     
  1120.     if ( !decompress )
  1121.     {
  1122.         Boolean IsText = ( gSufMap.Type == 'TEXT' );
  1123.         
  1124.         ascii = -1; /* -1 for unknown */
  1125.         macbinary = 0; /* still not declared OJO */
  1126.         
  1127.         if (( gPrefs.Compress.Keys ) && ( gApp.KeysMode != 0 ))
  1128.         {
  1129.             switch ( gApp.KeysMode )
  1130.             {
  1131.                 case kAppKeyASCII:
  1132.                     ascii = 1;
  1133.                     macbinary = 0;
  1134.                     break;
  1135.                 case kAppKeyBin:
  1136.                     ascii = 0;
  1137.                     macbinary = 0;
  1138.                     break;
  1139.                 case kAppKeyMBin:
  1140.                     ascii = 0;
  1141.                     macbinary = 1;
  1142.                     break;
  1143.                 default:
  1144.                     DoError(PROG_ERR,WARN_ERR,"Mala suerte, error del programador");
  1145.                     break;
  1146.             }
  1147.         }
  1148.         else
  1149.         {
  1150.             if ( gPrefs.Compress.IC )
  1151.             {
  1152.                 if ( gPrefs.Compress.IC_ASCII && IsText )
  1153.                 {
  1154.                     macbinary = 0;
  1155.                     ascii = 1;
  1156.                 }
  1157.                 else
  1158.                 {
  1159.                     ResolveFileType( fs, nil, &gSufMap, kRFTUpload | kRFTFromSpec | kRFTIC );
  1160.                         
  1161.                     if ( gSufMap.Found )
  1162.                     {
  1163.                         if ( gSufMap.MacFile && !gPrefs.Compress.IC_NotMB )
  1164.                         {
  1165.                             ascii = 0;
  1166.                             macbinary = 1;
  1167.                         }
  1168.                         else
  1169.                         {
  1170.                             ascii = !gSufMap.Binary;
  1171.                             macbinary = 0;
  1172.                         }
  1173.                         if ( IsText && gPrefs.Compress.IC_ASCII )
  1174.                         {
  1175.                             ascii = 1;
  1176.                             macbinary = 0;
  1177.                         }
  1178.                     }
  1179.                 }
  1180.             }
  1181.         }
  1182.         
  1183.         if ( ascii == -1 ) /* still unresolved */
  1184.         {
  1185.             switch ( gPrefs.Compress.Mode )
  1186.             {
  1187.                 case kComp_MASCII:
  1188.                     ascii = 1;
  1189.                     macbinary = 0;
  1190.                     break;
  1191.                 case kComp_MBin:
  1192.                     ascii = 0;
  1193.                     macbinary = 0;
  1194.                     break;
  1195.                 case kComp_MMB:
  1196.                     ascii = 0;
  1197.                     macbinary = 1;
  1198.                     break;
  1199.             }
  1200.             
  1201.             if ( (ascii == 0) && IsText && ( macbinary == 0 ) && ( gPrefs.Compress.Mode_a ) )
  1202.             {
  1203.                 ascii = 1;
  1204.                 macbinary = 0;
  1205.             }
  1206.         }
  1207.         
  1208.         if (( macbinary == 0 ) && ( istat.st_rsize != 0 ))
  1209.         {
  1210.             switch ( gPrefs.Compress.ResFork )
  1211.             {
  1212.                 case kComp_RFAsk:
  1213.                     DoNotification();
  1214.                     ParamText(fs->name,"\p","\p","\p");
  1215.                     switch ( CautionAlert( kAskRFID, nil ) )
  1216.                     {
  1217.                         case kAskRF_mb:
  1218.                             macbinary = 1;
  1219.                             break;
  1220.                         case kAskRF_not:
  1221.                             break;
  1222.                         case kAskRF_quit:
  1223.                             error = TRUE;
  1224.                             break;
  1225.                         default:
  1226.                             DoError(PROG_ERR,WARN_ERR,"Mala suerte, error del programador");
  1227.                             break;
  1228.                     }
  1229.                     break;
  1230.                 case kComp_RFMB:
  1231.                     macbinary = 1;
  1232.                     break;
  1233.                 case kComp_RFNot:
  1234.                     break;
  1235.                 case kComp_RFQuit:
  1236.                     error = TRUE;
  1237.                     break;
  1238.  
  1239.                 default:
  1240.                     break;
  1241.             }
  1242.         }
  1243.     }
  1244.     else /* decompress */
  1245.     {
  1246.         ascii = macbinary = -1;
  1247.         
  1248.         /* we have no clue about output file */
  1249.     }
  1250.     return error;
  1251. }
  1252. /* ========================================================================
  1253.  * Prompt for destination (compressed file)
  1254.  *
  1255.  */
  1256.  
  1257. OSErr PromptGZIPFile( FSSpec *fs, Str255 prompt )
  1258. {
  1259.     OSErr                 result = noErr;
  1260.     StandardFileReply    sfr;
  1261.     
  1262.     /* since this can be called from MacIO, after making some
  1263.      * processing, we need to post a notification
  1264.      */
  1265.     
  1266.     DoNotification( );
  1267.     StandardPutFile(prompt, fs->name, &sfr );
  1268.     
  1269.         
  1270.     if ( sfr.sfReplacing )
  1271.     {
  1272.         if ( 0 == memcmp( &ifs, &sfr.sfFile , sizeof(FSSpec) ) )
  1273.         {
  1274.             /* is this possible? */
  1275.             Str255ToCStr( ofname, sfr.sfFile.name );
  1276.             DoError(INPUT_ERR, WARN_ERR, "%s: cannot make %s onto itself",
  1277.             progname, ofname);
  1278.             return -1;
  1279.         }
  1280.         else
  1281.         {
  1282.             if (noErr != (err = FSpDelete(&sfr.sfFile)))
  1283.             {
  1284.                 Str255ToCStr( ofname, sfr.sfFile.name );
  1285.                 DoError(SYS_ERR, WARN_ERR, "Can't delete %s", ofname);
  1286.                 return err;
  1287.             }
  1288.             else
  1289.             {
  1290.                 *fs = sfr.sfFile;
  1291.             }
  1292.         }
  1293.     }
  1294.     else if ( sfr.sfGood )
  1295.     {
  1296.         Str255ToCStr( ofname, sfr.sfFile.name );
  1297.         *fs = sfr.sfFile;
  1298.     }
  1299.     else
  1300.     {
  1301.         result = -1;    
  1302.     }
  1303.     
  1304.     return result;
  1305. }
  1306.  
  1307. OSErr MakeOFSSpec( FSSpec *fs , Str255 prompt )
  1308. {
  1309.     StandardFileReply    sfr;
  1310.     Boolean                done;
  1311.  
  1312.     FSSpec                fSpec;
  1313.     Boolean                changedFlag;
  1314.     
  1315.     struct stat            fldrStat;
  1316.     
  1317.     
  1318.     done = TRUE;
  1319.         
  1320.     if ( gApp.Prompt )
  1321.     {
  1322.         if ( noErr != ( err = PromptGZIPFile( fs, prompt )) )
  1323.             return err;
  1324.     }
  1325.     else if ( gPrefs.Folder.UseDestFolder && ( nil != gApp.DFolder ))
  1326.     {
  1327.         if( noErr == (err = ResolveAlias(nil, gApp.DFolder, &fSpec, &changedFlag)))
  1328.         {
  1329.             err = fs_stat( &fSpec, &fldrStat );
  1330.             if (( S_ISDIR ( fldrStat.st_mode ) ) && ( noErr == err ))
  1331.             {
  1332.                 fs->vRefNum = fldrStat.st_dev;
  1333.                 fs->parID = fldrStat.st_ino;
  1334.             }
  1335.         }
  1336.     
  1337.         if (noErr != err)
  1338.         {
  1339.             /* display alert and prompt for new destination */
  1340.             /* unset use folder too */
  1341.             
  1342.             DoError( SYS_ERR, WARN_ERR, "Sorry, Can't find your destination folder");
  1343.             gPrefs.Folder.UseDestFolder = FALSE;
  1344.             
  1345.             if ( noErr != PromptGZIPFile( fs, prompt ) )
  1346.                 return err;
  1347.         }
  1348.         else
  1349.         {
  1350.             done = FALSE;
  1351.         }
  1352.  
  1353.     }
  1354.     else
  1355.         done = FALSE;
  1356.         
  1357.     if ( !done )
  1358.     {
  1359.         /* replace if force, else  prompt */
  1360.         FInfo    foo;
  1361.         
  1362.         err = FSpGetFInfo ( fs, &foo );
  1363.         
  1364.         if ( err != fnfErr )
  1365.         {
  1366.             if( err != noErr )
  1367.             {
  1368.                 return err;
  1369.             }
  1370.             /* ofs exists */
  1371.             else if ( gPrefs.gzip.Force )
  1372.             {
  1373.                 if (noErr != (err = FSpDelete(&sfr.sfFile)))
  1374.                 {
  1375.                     Str255ToCStr( ofname, sfr.sfFile.name );
  1376.                     DoError(SYS_ERR, WARN_ERR, "Can't delete %s", ofname);
  1377.                     return err;
  1378.                 }
  1379.             }
  1380.             else
  1381.             {
  1382.                 if ( noErr != (err = PromptGZIPFile( fs, prompt )) )
  1383.                 {
  1384.                     return err;
  1385.                 }
  1386.             }
  1387.         }
  1388.     }
  1389.     
  1390.     return noErr;
  1391. }
  1392.  
  1393.